package com.study.juc.atomics;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;

/**
 * @program: juc-study
 * @author: jzhou
 * @date: 2022-08-17 10:57
 * @version: 1.0
 * @description: LongAdder高性能对比Code演示
 *
 * 50个线程，每个线程点赞 100W 次，总点赞数出来
 * 不同方法结果
 * ----costTime: 2389 毫秒	 clickBySync result: 50000000
 * ----costTime: 1204 毫秒	 clickByAtomicLong result: 50000000
 * ----costTime: 198 毫秒	 clickByLongAdder result: 50000000
 * ----costTime: 219 毫秒	 clickByLongAccumulator result: 50000000
 **/
public class LongAdderDemo {
	public static void main(String[] args) throws InterruptedException {
		// 线程操作资源类
		ClickNumberNet clickNumberNet = new ClickNumberNet();

		long startTime;
		long endTime;
		CountDownLatch countDownLatch = new CountDownLatch(50);
		CountDownLatch countDownLatch2 = new CountDownLatch(50);
		CountDownLatch countDownLatch3 = new CountDownLatch(50);
		CountDownLatch countDownLatch4 = new CountDownLatch(50);

		// 使用同步方法累计
		startTime = System.currentTimeMillis();
		for (int i = 1; i <= 50; i++) {
			new Thread(() -> {
				try {
					for (int j = 1; j <= 100 * 10000; j++) {
						clickNumberNet.clickBySync();
					}
				} finally {
					countDownLatch.countDown();
				}
			}, String.valueOf(i)).start();
		}
		countDownLatch.await();
		endTime = System.currentTimeMillis();
		System.out.println("----costTime: " + (endTime - startTime) + " 毫秒" + "\t clickBySync result: " + clickNumberNet.number);

		// 使用AtomicLong类累加
		startTime = System.currentTimeMillis();
		for (int i = 1; i <= 50; i++) {
			new Thread(() -> {
				try {
					for (int j = 1; j <= 100 * 10000; j++) {
						clickNumberNet.clickByAtomicLong();
					}
				} finally {
					countDownLatch2.countDown();
				}
			}, String.valueOf(i)).start();
		}
		countDownLatch2.await();
		endTime = System.currentTimeMillis();
		System.out.println("----costTime: " + (endTime - startTime) + " 毫秒" + "\t clickByAtomicLong result: " + clickNumberNet.atomicLong);

		// 使用 LongAdder 类累加
		startTime = System.currentTimeMillis();
		for (int i = 1; i <= 50; i++) {
			new Thread(() -> {
				try {
					for (int j = 1; j <= 100 * 10000; j++) {
						clickNumberNet.clickByLongAdder();
					}
				} finally {
					countDownLatch3.countDown();
				}
			}, String.valueOf(i)).start();
		}
		countDownLatch3.await();
		endTime = System.currentTimeMillis();
		System.out.println("----costTime: " + (endTime - startTime) + " 毫秒" + "\t clickByLongAdder result: " + clickNumberNet.longAdder.sum());

		// 使用 LongAccumulator 类累加
		ExecutorService executorService = Executors.newFixedThreadPool(4);
		startTime = System.currentTimeMillis();
		for (int i = 1; i <= 50; i++) {
			executorService.execute(() -> {
				try {
					for (int j = 1; j <= 100 * 10000; j++) {
						clickNumberNet.clickByLongAccumulator();
					}
				} finally {
					countDownLatch4.countDown();
				}
			});
		}
		countDownLatch4.await();
		executorService.shutdown();
		endTime = System.currentTimeMillis();
		System.out.println("----costTime: " + (endTime - startTime) + " 毫秒" + "\t clickByLongAccumulator result: " + clickNumberNet.longAccumulator.longValue());
	}
}


class ClickNumberNet {
	int number = 0;
	public synchronized void clickBySync() {
		number++;
	}

	AtomicLong atomicLong = new AtomicLong(0);
	public void clickByAtomicLong() {
		atomicLong.incrementAndGet();
	}

	LongAdder longAdder = new LongAdder();
	public void clickByLongAdder() {
		longAdder.increment();
	}

	LongAccumulator longAccumulator = new LongAccumulator((x, y) -> x + y, 0);
	public void clickByLongAccumulator() {
		longAccumulator.accumulate(1);
	}
}